package empty

import Chisel.log2Ceil
import chipsalliance.rocketchip.config.{Config, Parameters}
import chisel3._
import chisel3.internal.sourceinfo.SourceInfo
import chisel3.stage.ChiselStage
import chisel3.util.random.FibonacciLFSR
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.amba.axi4._
import freechips.rocketchip.unittest._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.config._
import chisel3.util.IrrevocableIO

object myAxiUtil{
//首先是为不同的模块定义不同的参数，diplomacy提供了标准的定义，以供使用
//1. AXI4MasterPortParameters：依赖于AXI4SlaveParameters
//2. AXI4SlavePortParameters：依赖于AXI4MasterParameters
//这一步对应于Add.scala中的三个case class
//这里我们直接继承这些case class并且进行自定义：
// case class myAXI4MasterParameters(name:String="Axi4Master", id:IdRange=IdRange(0,1)) extends AXI4MasterParameters(name, id)
// case class myAXI4MasterPortParameters(masters:Seq[AXI4MasterParameters]=Seq(myAXI4MasterParameters())) extends AXI4MasterPortParameters(masters)
    val myAXI4MasterParameters =  AXI4MasterParameters(name="Axi4Master1", id=IdRange(0,1))
    val myAXI4MasterPortParameters = Seq(AXI4MasterPortParameters(masters=Seq(myAXI4MasterParameters)))
    val myAXI4MasterParameters1 =  AXI4MasterParameters(name="Axi4Master2", id=IdRange(0,1))
    val myAXI4MasterPortParameters1 = Seq(AXI4MasterPortParameters(masters=Seq(myAXI4MasterParameters1)))

//两个slave，因此定义两个 AXI4SlavePortParameters
// case class myAXI4SlaveParameters1(
//     address: Seq[AddressSet] = Seq(AddressSet(0x80000000L, 0xffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters1(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters1()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
    val myAXI4SlaveParameters1 = AXI4SlaveParameters(
        address = Seq(AddressSet(0x80000000L, 0xffff)),
        supportsWrite= TransferSizes(1,64),
        supportsRead = TransferSizes(1,64)
        )
    val myAXI4SlavePortParameters1 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters1), beatBytes=64))


// case class myAXI4SlaveParameters2(
//     address: Seq[AddressSet] = Seq(AddressSet(0x90000000L, 0xffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters2(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters2()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
    val myAXI4SlaveParameters2 = AXI4SlaveParameters(
        address = Seq(AddressSet(0x90000000L, 0xffff)),
        supportsWrite = TransferSizes(1,64),
        supportsRead  = TransferSizes(1,64)
        )
    val myAXI4SlavePortParameters2 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters2), beatBytes=64))

// case class myAXI4SlaveParameters3(
//     address: Seq[AddressSet] = Seq(AddressSet(0x00000000L, 0xffffffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters3(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters3()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
    val myAXI4SlaveParameters3 = AXI4SlaveParameters(
        address = Seq(AddressSet(0x00000000L, 0xffffffffL)),
        supportsWrite = TransferSizes(1,64),
        supportsRead  = TransferSizes(1,64)
        )
    val myAXI4SlavePortParameters3 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters3), beatBytes=64))
}
//然后是为定义不同类型的node，以便于和后续模块绑定，主要是两个driver模块、xbar模块和一个accept模块
//1. case class AXI4MasterNode(portParams: Seq[AXI4MasterPortParameters])：用于driver模块
//2. case class AXI4SlaveNode(portParams: Seq[AXI4SlavePortParameters])：用于accept模块
//3. case class AXI4NexusNode(
//  masterFn:       Seq[AXI4MasterPortParameters] => AXI4MasterPortParameters,
//  slaveFn:        Seq[AXI4SlavePortParameters]  => AXI4SlavePortParameters)(
//  implicit valName: ValName):用于xbar模块

//编写AXI4Xbar模块，这一步省略，因为rocket chip库中有，并且已经实现了与AXI4NexusNode节点的绑定，对应于Add.scala中的Adder类；

//编写driver模块
class axi4Driver()(implicit valName:ValName, p:Parameters) extends LazyModule {
    import myAxiUtil._
    val node = AXI4MasterNode(myAXI4MasterPortParameters)
    //val node = AXI4MasterNode()

    lazy val module = new LazyModuleImp (this) {

    }
    override lazy val desiredName = "axi4Driver"
}

//编写accept模块
class axi4Accept()(implicit valName:ValName, p:Parameters) extends  LazyModule {
    import myAxiUtil._
    val node = AXI4SlaveNode(myAXI4SlavePortParameters3)//使用myAXI4SlavePortParameters3，接受32bit的所有参数；

    lazy val module = new LazyModuleImp (this) {

    }
    override lazy val desiredName = "axi4Accept"
}

//编写顶层
class xbarTestHarness()(implicit valName:ValName, p:Parameters) extends LazyModule {
    import myAxiUtil._
    val numSlaves = 2
    //two axi4 drivers
    val drivers = Seq.fill(numSlaves){
        LazyModule(new axi4Driver())
    }
    //val dirvers = LazyModule(new axi4Driver())
    //one axi4 accepter
    val accept = LazyModule(new axi4Accept())
    //axi4 interconnect
    val xbar = AXI4Xbar()//xbar is a nexusNode

    //connection
    accept.node := xbar
    drivers.foreach {d => (xbar := d.node)}
    //xbar := dirvers.node

    lazy val module = new LazyModuleImp (this) {

    }
    override lazy val desiredName = "xbarTestHarness"

}

class myAXI4XbarFuzzTest(name: String="XBar2to1", txns: Int=5000, nMasters: Int=2, nSlaves: Int=1, myAddressSet:Seq[AddressSet]=Seq(AddressSet(0x0L,0xfffffffL)), beatBytes:Int=64)(implicit p: Parameters)
  extends AXI4XbarFuzzTest(name,txns, nMasters, nSlaves)(p){
    //val myAddressSet = Seq(AddressSet(0x0L,0xfffffffL))
    require(myAddressSet.length==nSlaves,"myAddressSet length must be equal to nSlaves")
    //override val slaves = myAddressSet.map(s => LazyModule(new AXI4RAM(address=s,beatBytes=beatBytes)))
}

class myAXI4XbarFuzzTest2(name: String="XBar2to1", txns: Int=5000, nMasters: Int=2, nSlaves: Int=1,myAddressSet:Seq[AddressSet]=Seq(AddressSet(0x0L,0xfffffffL)), beatBytes:Int=64)(implicit p: Parameters) extends LazyModule
{
    val xbar = AXI4Xbar()
    val slaveSize = 0x1000
    val masterBandSize = slaveSize >> log2Ceil(nMasters)
    def filter(i: Int) = TLFilter.mSelectIntersect(AddressSet(i * masterBandSize, ~BigInt(slaveSize - masterBandSize)))

    //val slaves = Seq.tabulate(nSlaves) { i => LazyModule(new AXI4RAM(AddressSet(slaveSize * i, slaveSize-1))) }
    require(myAddressSet.length==nSlaves,"myAddressSet length must be equal to nSlaves")
    val slaves = myAddressSet.map(s => LazyModule(new AXI4RAM(address=s,beatBytes=beatBytes)))
    slaves.foreach { s => (s.node
      := AXI4Fragmenter()
      //:= AXI4Buffer(BufferParams.flow)
      //:= AXI4Buffer(BufferParams.flow)
      //:= AXI4Delayer(0.25)
      := xbar) }

    val masters = Seq.fill(nMasters) { LazyModule(new TLFuzzer(txns, 4, nOrdered = Some(1))) }
    masters.zipWithIndex.foreach { case (m, i) => (xbar
      //:= AXI4Delayer(0.25)
      := AXI4Deinterleaver(4096)//cannot be removed
      := TLToAXI4()
      := TLFilter(filter(i))
      := TLRAMModel(s"${name} Master $i")//cannot be removed
      := m.node) }

    lazy val module = new LazyModuleImp(this) with UnitTestModule {
        io.finished := masters.map(_.module.io.finished).reduce(_ || _)
    }
}

object AxiMain extends App {
    println("Generating Hardware")
    //  val verilog = (new ChiselStage).emitVerilog(LazyModule(new AdderTestHarness()(Parameters.empty)).module, Array("--target-dir","generated"))
    //  println (s"``` verilog \n$verilog```")
    //implicit val valName:ValName = new ValName("MyAxiCrossbar")
    val myAddressSet = Seq(AddressSet(0x0L,0xffffffffL))
    val myAddressSet2 = Seq(AddressSet(0x0L,0xffbfffffL), AddressSet(0xffc00000L, 0x3fffff))
    implicit val p = Parameters.empty
    //val verilog = (new ChiselStage).emitVerilog(LazyModule(new xbarTestHarness()).module,Array("--target-dir", "generated"))
    //val verilog2 = (new ChiselStage).emitVerilog(LazyModule(new AXI4XbarFuzzTest("Xbar DUT21", 5000, 2,1)).module,Array("--target-dir", "generated"))
    //val verilog3 = (new ChiselStage).emitVerilog(LazyModule(new myAXI4XbarFuzzTest2(myAddressSet=myAddressSet)).module,Array("--target-dir", "generated"))
    val verilog4 = (new ChiselStage).emitVerilog(LazyModule(new myAXI4XbarFuzzTest2(myAddressSet=myAddressSet2,nSlaves = 2)).module,Array("--target-dir", "generated"))
}
